﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Xml.Linq;
using System.IO;

namespace Ornament.NHibernates.Configurations
{
    /// <summary>
    /// 
    /// </summary>
    public sealed class NHibernateSetting
    {
        private readonly XDocument docment;
        private readonly string fileName;
        private readonly XNamespace xNamespace;

        public NHibernateSetting(string file)
        {
            if (String.IsNullOrEmpty(file))
                throw new ArgumentNullException("file");

            docment = XDocument.Load(file);
            this.fileName = file;
            this.xNamespace = docment.Root.Name.Namespace;
        }


        public int Count
        {
            get
            {
                IEnumerable<XElement> s = from sessionFactory in docment.Root.Elements(xNamespace + "session-factory")
                                          select
                                              sessionFactory;
                return (new List<XElement>(s)).Count;
            }
        }

        public SessionFactory this[string sessionFactoryName]
        {
            get
            {
                IEnumerable<XElement> s = from sessionFactory in docment.Root.Elements(xNamespace + "session-factory")
                                          where sessionFactory.Attribute("name").Value == sessionFactoryName
                                          select sessionFactory;

                XElement result = s.SingleOrDefault();
                if (result != null && !result.IsEmpty)
                {
                    return new SessionFactory(result);
                }
                throw new ArgumentOutOfRangeException(sessionFactoryName);
            }
        }

        public IList<string> FindNHibernateAssembly()
        {
            var result = new List<string>();
            Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
            foreach (Assembly asm in assemblies)
            {
                //filter .net inner assembly
                string asmName = asm.GetName().Name;
                if (asmName.StartsWith("System") || asmName.StartsWith("Microsoft") || asmName.StartsWith("mscorlib") ||
                    asmName.StartsWith("Anonymously") || asmName.StartsWith("App"))
                    continue;
                try
                {
                    string[] names = asm.GetManifestResourceNames();
                    foreach (string resource in names)
                    {
                        if (resource.ToLower().EndsWith(".hbm.xml"))
                        {
                            result.Add(asm.GetName().Name);
                            break;
                        }
                    }
                }
                catch
                {
                }
            }
            result.Sort();
            return result;
        }

        public string[] GetSessionFactoryNames()
        {
            IEnumerable<XElement> s = from sessionFactory in docment.Root.Elements(xNamespace + "session-factory")
                                      select sessionFactory;
            var result = new List<string>();
            foreach (XElement element in s)
            {
                result.Add(element.Attribute("name").Value);
            }
            return result.ToArray();
        }

        public void Save()
        {
            docment.Save(fileName);
        }

        public static NHibernateSetting Create(string file, string sessionFactoryName)
        {
            const string NHibernateContent =
                @"<?xml version=""1.0"" encoding=""utf-8""?>
<hibernate-configuration xmlns=""urn:nhibernate-configuration-2.2"">
  {0}
</hibernate-configuration>";

            const string SessionFactory =
                @"<session-factory name=""{0}"">    
    <property name=""connection.provider"">NHibernate.ConnectionString.DriverConnectionProvider</property>
    <property name=""connection.driver_class"">NHibernate.Driver.SqlClientDriver</property>        
    <property name=""connection.connection_string_name"">nhconnection</property>
    <property name=""show_sql"">false</property>
    <property name=""dialect"">NHibernate.Dialect.MsSql2005Dialect</property>
    <property name=""use_outer_join"">true</property>    
    <property name=""command_timeout"">500</property>
    <property name=""query.substitutions"">true 1, false 0, yes 1, no 0</property>
  </session-factory>";
            if (!File.Exists(file))
            {
                using (var sw = new StreamWriter(file))
                {
                    string content = String.Format(SessionFactory, sessionFactoryName);
                    sw.Write(String.Format(NHibernateContent, content));
                    sw.Flush();
                    sw.Close();
                }
            }
            return new NHibernateSetting(file);
        }
    }
}